/************************************************************************
This file is part of java core libraries for the simpleRTJ virtual machine.

This file is covered by the GNU GPL with the following exception:
  As a special exception, the copyright holders of this library give you permission
  to link this library with independent modules to produce an executable, regardless
  of the license terms of these independent modules, and to copy and distribute the
  resulting executable under terms of your choice, provided that you also meet, for
  each linked independent module, the terms and conditions of the license of that
  module. An independent module is a module which is not derived from or based on
  this library. If you modify this library, you may extend this exception to your
  version of the library, but you are not obligated to do so. If you do not wish
  to do so, delete this exception statement from your version.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL RTJ COMPUTING BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Copyright (c) 2000-2002 RTJ Computing Pty. Ltd. All rights reserved.
***********************************************************************/
package javax.events;

import java.lang.*;

/**
 * Timer is a special type of AsyncEvent that require additional native support to
 * implement single shot and periodic timing events.
 * Maximum number of software timers is compiled into native code and is represented
 * by MAX_TIMERS variable. Maximum supported timeout value is 65535 milliseconds.
 * Two timer AsyncEventHandler are supported:<br>
 * - SingleShotTimerHandler<br>
 * - PeriodicTimerHandler
 * <p>
 * Note1: There can be only one handler associated with each timer. <br>
 * Note2: Timer event handler must be always present at index zero when registered
 * with Events.addEvent method.
 */
public class Timer extends AsyncEvent
{
    /**
     * Number of software timers is retrieved from native code.
     */
    public static int MAX_TIMERS = getTimersCount();
    /**
     * Holds timeout values for each software timer.
     */
    private static int timeouts[] = new int[MAX_TIMERS];
    /**
     * Timer constructor.
     */
    public Timer()
    {
        super(MAX_TIMERS);
    }

    /**
     * Calls handler methods for each registered timer event handler. Only
     * those timer handlers are called for which timeout has expired.
     */
    public void fire()
    {
        while (true)
        {
            int id = getExpiredId();
            if (id == -1)
                break;

            if (id < evHandlers.length && evHandlers[id] != null)
            {
                // reschedule timer event for periodic timer
                if (evHandlers[id] instanceof PeriodicTimerHandler)
                    start0(id, timeouts[id]);

                evHandlers[id].handleAsyncEvent();
            }
        }
    }

    /**
     * Starts the specified timer.
     * @param handler   reference to a timer handler that should be started.
     * @param timeout       timeout value that is associated with this timer
     */
    public void start(AsyncEventHandler handler, int timeout)
    {
        for (int i=0; i < evHandlers.length; i++)
        {
            if (evHandlers[i] != null && handler == evHandlers[i])
            {
                timeouts[i] = timeout;
                start0(i, timeout);
            }
        }
    }

    /**
     * Enables the specified timer.
     * @param handler   reference to a timer handler that should be enabled.
     */
    public void enable(AsyncEventHandler handler)
    {
        for (int i=0; i < evHandlers.length; i++)
        {
            if (evHandlers[i] != null && handler == evHandlers[i])
                start0(i, timeouts[i]);
        }
    }

    /**
     * Disables the specified timer.
     * @param handler   reference to a timer handler that should be disabled.
     */
    public void disable(AsyncEventHandler handler)
    {
        for (int i=0; i < evHandlers.length; i++)
        {
            if (evHandlers[i] != null && handler == evHandlers[i])
                start0(i, 0);
        }
    }

    /**
     * Returns id of the handler for which timeout value has expired.
     * @return ID of an expired timer, -1 if no timer has expired.
     */
    private native int getExpiredId();

    /**
     * Starts the timer with specified ID.
     * @param timerId   ID of a timer that should be started
     * @param timeout   timeout value in milliseconds. Max allowed value is 65535.
     *                  Zero value disables the timer.
     */
    private native void start0(int timerId, int timeout);

    /**
     * Native method returning the count of implemented software timers.
     * @return max. number of software timers that Timer class can use.
     */
    private static native int getTimersCount();
}


